package com.example.myapplication.widgets.wave;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import com.example.myapplication.R;
import com.example.myapplication.widgets.CanvasUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 曲线图
 */
public class WaveView extends View {

    // 坐标轴上描述性文字的空间大小
    private int mBottomTextHeight;
    private int mLeftTextWidth, mLeftTextMargin;
    private int mShowTextColor;
    private int mShowBackgroundColor;
    private int mShowPaddingVertical, mShowPaddingHorizontal;

    private List<WaveConfigData> mWaves;// 数值集合
    private int mCoordinateYCount = 6;// y轴的分块数
    private String[] mCoordinateXValues;// 外界传入,x轴的值
    private float[] mCoordinateYValues;// 动态计算,y轴的值
    // 网格尺寸
    private int mGridWidth, mGridHeight;
    // 所有曲线中所有数据中的最大值
    private float mGlobalMaxValue;// 用于确认是否需要调整坐标系
    private float mMaxYValue;// 所有数据线里面，最大的Y轴数据
    private Paint mCoordinatorPaint;
    private Paint mTextPaint;
    private Paint mWrapPaint;
    private PathEffect mCoordinateDashedPathEffect;
    private PathEffect mWaveDashedPathEffect;
    private float mAnimProgress = 1;
    private final int mShowCircleRadius = 15; // 点击时展示的圆环半径

    public WaveView(Context context) {
        this(context, null);
    }

    public WaveView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
        mBottomTextHeight = dp2px(40);// X轴底部字体的高度
        mLeftTextWidth = mBottomTextHeight;// Y轴左边字体的宽度
        mLeftTextMargin = dp2px(4);
        int coordinatorTextSize = sp2px(12);
        int textColor = Color.GRAY;
        int coordinatorColor = Color.LTGRAY;
        int showTextSize = coordinatorTextSize;
        mShowPaddingVertical = mShowPaddingHorizontal = dp2px(10);
        mShowTextColor = Color.WHITE;
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.WaveView);
            mBottomTextHeight = typedArray.getDimensionPixelSize(R.styleable.WaveView_bottomTextHeight, mBottomTextHeight);
            mLeftTextWidth = typedArray.getDimensionPixelSize(R.styleable.WaveView_leftTextWidth, mLeftTextWidth);
            mLeftTextMargin = typedArray.getDimensionPixelSize(R.styleable.WaveView_leftTextMargin, mLeftTextMargin);
            coordinatorTextSize = typedArray.getDimensionPixelSize(R.styleable.WaveView_coordinateTextSize, coordinatorTextSize);
            textColor = typedArray.getColor(R.styleable.WaveView_coordinateTextColor, textColor);
            coordinatorColor = typedArray.getColor(R.styleable.WaveView_coordinateColor, coordinatorColor);

            showTextSize = typedArray.getDimensionPixelSize(R.styleable.WaveView_showTextSize, showTextSize);
            mShowBackgroundColor = typedArray.getColor(R.styleable.WaveView_showBackgroundColor, mShowBackgroundColor);
            mShowPaddingVertical = typedArray.getDimensionPixelSize(R.styleable.WaveView_showPaddingVertical, mShowPaddingVertical);
            mShowPaddingHorizontal = typedArray.getDimensionPixelSize(R.styleable.WaveView_showPaddingHorizontal, mShowPaddingHorizontal);
            typedArray.recycle();
        }

        // 初始化数据集合的容器
        mWaves = new ArrayList<>();
//        mTopUnitHeight = dp2px(10);// 顶部Y轴的单位
        // 初始化坐标轴Paint
        mCoordinatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mCoordinatorPaint.setColor(coordinatorColor);
        mCoordinatorPaint.setStrokeWidth(dp2px(0.5f));
        // 初始化文本Paint
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mTextPaint.setColor(textColor);
        mTextPaint.setTextSize(coordinatorTextSize);
        // 初始化曲线Paint
        mWrapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mWrapPaint.setTextSize(showTextSize);
        mWrapPaint.setStrokeWidth(dp2px(2));

        mCoordinateDashedPathEffect = new DashPathEffect(new float[]{9, 9}, 5);
        mWaveDashedPathEffect = new DashPathEffect(new float[]{20, 10}, 10);
    }

    public void clear() {
        mMaxYValue = 0;
        mGlobalMaxValue = 0;
        mAnimProgress = 1;
        mWaves.clear();
    }

    /**
     * 配置坐标轴信息
     *
     * @param coordinateYCount  Y 轴坐标轴上值的数量
     * @param coordinateXValues X 坐标轴上的数值
     */
    public void setupCoordinator(int coordinateYCount, String... coordinateXValues) {
        mCoordinateYCount = coordinateYCount;
        mCoordinateXValues = coordinateXValues;
    }

    public void addWave(int color, float... values) {
        addWave(color, 0, -1, false, values);
    }

    public void addWave(int color, int dashStartPoint, float... values) {
        addWave(color, 0, dashStartPoint, false, values);
    }

    public void addWaveCoverRegion(int color, float... values) {
        addWave(color, 0, -1, true, values);
    }

    public void addWaveCoverRegion(int color, int linearGradientEndColor, float... values) {
        addWave(color, linearGradientEndColor, -1, true, values);
    }

    /**
     * 添加一条曲线, 确保与横坐标的数值对应
     */
    public void addWave(int color, int linearGradientEndColor, int dashStartPoint, boolean isCoverRegion, float... values) {
        WaveConfigData waveConfigData = new WaveConfigData(color, linearGradientEndColor, isCoverRegion, values);
        waveConfigData.dashStartPoint = dashStartPoint;
        mWaves.add(waveConfigData);
        // 根据value的值去计算纵坐标的数值
        float maxValue = 0;
        for (float value : values) {
            maxValue = Math.max(maxValue, value);
        }
        mMaxYValue = Math.max(mMaxYValue, maxValue);
        if (maxValue < mGlobalMaxValue) return;
//        mGlobalMaxValue = maxValue;
        // 保证网格的数值都为 5 的倍数
//        float gridValue = mGlobalMaxValue / (mCoordinateYCount - 2);
//        if (gridValue % 5 != 0) {
//            gridValue += 5 - (gridValue % 5);
//        }
        float gridValue = 1;
        float tempMaxY = mMaxYValue;
        while ((tempMaxY /= 10f) > 1) {
            gridValue *= 10;
        }
        if (tempMaxY >= 0.5)
            gridValue *= 2;
        mGlobalMaxValue = gridValue * (mCoordinateYCount - 1);
        // 给纵坐标的数值赋值
        mCoordinateYValues = new float[mCoordinateYCount];
        for (int i = 0; i < mCoordinateYCount; i++) {
            mCoordinateYValues[i] = i * gridValue;
        }
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawCoordinate(canvas);
        drawWrap(canvas);
        drawShowPop(canvas);
    }

    private ValueAnimator mAnimator;

    public void showAnimator() {
        if (mAnimator == null) {
            mAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
            mAnimator.addUpdateListener(animation -> {
                mAnimProgress = (float) animation.getAnimatedValue();
                invalidate();
            });
        }
        mAnimator.start();
    }

    public void cancelAnimator() {
        if (mAnimator != null)
            mAnimator.cancel();
    }

    /**
     * 获取X轴位置
     */
    private int getXCoordinator() {
        return getHeight() - getPaddingBottom() - mBottomTextHeight;
    }

    /**
     * 获取Y轴位置
     */
    private int getYCoordinator() {
        return getPaddingStart() + mLeftTextWidth + mLeftTextMargin;
    }

    /**
     * 绘制坐标系
     */
    private void drawCoordinate(Canvas canvas) {
        Point start = new Point();
        Point stop = new Point();
        // 1. 绘制横轴线和纵坐标单位   只绘制坐标轴X轴和实际最大值的横轴线
        int xLineCount = mCoordinateYValues.length;
        mGridHeight = (getXCoordinator() - getPaddingTop()) / (xLineCount - 1);

        float offsetY = CanvasUtil.getDrawTextOffsetY(mTextPaint);
        String drawText;
        float baseLine, left;

        // region 只绘制最高点
//        mCoordinatorPaint.setPathEffect(null);
//        start.x = getYCoordinator();
//        start.y = getXCoordinator();
//        stop.x = getWidth() - getPaddingEnd();
//        stop.y = start.y;
//      // 绘制X横轴线
//        canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);
        // 绘制纵坐标单位
//        drawText = String.valueOf((int) mCoordinateYValues[0]);
//        baseLine = start.y + offsetY;
//        left = getYCoordinator() - mTextPaint.measureText(drawText) - mLeftTextMargin;
//        canvas.drawText(drawText, left, baseLine, mTextPaint);

        // 绘制最大值的横轴线
//        float yHeight = mGridHeight * (mCoordinateYCount - 1);
//        float maxY = mCoordinateYValues[mCoordinateYCount - 1];// Y轴坐标的最大值
//        mCoordinatorPaint.setPathEffect(mCoordinateDashedPathEffect);
//        start.y = stop.y = (int) (getXCoordinator() - yHeight * (mMaxYValue / maxY));
//        // 绘制横轴线
//        canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);
//        // 绘制纵坐标单位
//        drawText = String.valueOf((int) mMaxYValue);
//        baseLine = start.y + offsetY;
//        left = getYCoordinator() - mTextPaint.measureText(drawText) - mLeftTextMargin;
//        canvas.drawText(drawText, left, baseLine, mTextPaint);
        // endregion

        boolean changeToK = mCoordinateYValues[1] >= 2000;
        for (int i = 0; i < xLineCount; i++) {
            if (i > 0) {
                mCoordinatorPaint.setPathEffect(mCoordinateDashedPathEffect);
            } else {
                mCoordinatorPaint.setPathEffect(null);
            }
            start.x = getYCoordinator();
            start.y = getXCoordinator() - mGridHeight * i;
            stop.x = getWidth() - getPaddingEnd();
            stop.y = start.y;
            // 绘制横轴线
            canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);
            // 绘制纵坐标单位
            drawText = String.valueOf(i > 0 && changeToK?
                    String.format(Locale.getDefault(), "%dK", (int)(mCoordinateYValues[i] / 1000))
                    : (int) mCoordinateYValues[i]);
            baseLine = start.y + offsetY;
            left = getYCoordinator() - mTextPaint.measureText(drawText) - mLeftTextMargin;
            canvas.drawText(drawText, left, baseLine, mTextPaint);
        }

        // 2. 绘制纵轴线和横坐标单位
        int yLineCount = mCoordinateXValues.length;
        mGridWidth = (getWidth() - getYCoordinator() - getPaddingEnd()) / (yLineCount - 1);
        start.y = getPaddingTop();
        stop.y = getXCoordinator();
        for (int i = 0; i < yLineCount; i++) {
            if (i > 0) {
                mCoordinatorPaint.setPathEffect(mCoordinateDashedPathEffect);
            } else {
                mCoordinatorPaint.setPathEffect(null);
            }
            start.x = stop.x = getYCoordinator() + mGridWidth * i;
            // 绘制纵轴线
            canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);
            // 绘制横坐标单位
            drawText = mCoordinateXValues[i];
            baseLine = getXCoordinator() + mBottomTextHeight / 2f + offsetY;
            left = start.x - mTextPaint.measureText(drawText) / 2;
            canvas.drawText(drawText, left, baseLine, mTextPaint);
        }
    }

    /**
     * 绘制曲线
     */
    private void drawWrap(Canvas canvas) {
        // 对canvas进行裁剪，形成动画效果
        canvas.clipRect(new RectF(0, 0, getWidth() * mAnimProgress, getHeight()));

        float yHeight = mGridHeight * (mCoordinateYCount - 1);
        float waveMinY, x, y, preX = 0, preY = 0;
        Path path = new Path();
        boolean hadDrawMaxYLine = false;
        float maxY = mCoordinateYValues[mCoordinateYCount - 1];// Y轴坐标的最大值
        for (WaveConfigData wave : mWaves) {
            waveMinY = Float.MAX_VALUE;
            for (int index = 0; index < wave.values.length; index++) {
                // 计算点的位置
                x = getYCoordinator() + mGridWidth * index;
                y = getXCoordinator() - yHeight * (wave.values[index] / maxY);
                waveMinY = Math.min(waveMinY, y);
                if (index == 0)
                    path.moveTo(x, y);
                else {
                    float centerX = preX + mGridWidth / 2f;
                    path.cubicTo(centerX, preY, centerX, y, x, y);//创建三阶贝塞尔曲线
                }
                preX = x;
                preY = y;

                if (wave.dashStartPoint >= 0 && wave.dashStartPoint == index && index + 1 < wave.values.length) {
                    // 需要绘制虚线，则先把之前的实线绘制掉
                    drawWavePath(wave, canvas, path, waveMinY);
                    // 切换画笔为虚线
                    mWrapPaint.setPathEffect(mWaveDashedPathEffect);
                    path.reset();
                    path.moveTo(x, y);
                }
            }
            drawWavePath(wave, canvas, path, waveMinY);
            path.reset();
        }
    }

    private void drawWavePath(WaveConfigData wave, Canvas canvas, Path path, float waveMinY) {
        if (wave.isCoverRegion) { // 如果是覆盖区域，则连上坐标轴的右下角和原点，圈出整个区域
            mWrapPaint.setStyle(Paint.Style.FILL);
            path.lineTo(getWidth() - getPaddingEnd(), getXCoordinator());
            path.lineTo(getYCoordinator(), getXCoordinator());
            path.close();
        } else {
            mWrapPaint.setStyle(Paint.Style.STROKE);
        }
        if (wave.linearGradientEndColor != 0) { // 如果有渐变颜色endColor，则设置渐变色shader
            LinearGradient linearGradient = new LinearGradient(
                    getYCoordinator() + mGridWidth * wave.values.length / 2f, waveMinY,
                    getYCoordinator() + mGridWidth * wave.values.length / 2f, getXCoordinator(),
                    wave.color, wave.linearGradientEndColor, Shader.TileMode.CLAMP);
            mWrapPaint.setShader(linearGradient);
        } else {
            mWrapPaint.setShader(null);
            mWrapPaint.setColor(wave.color);
        }
        canvas.drawPath(path, mWrapPaint);
        // 清除虚线的配置
        mWrapPaint.setPathEffect(null);
        // 清除渐变色的配置
        mWrapPaint.setShader(null);
    }

    /**
     * 绘制点击展示的数据弹窗
     */
    private void drawShowPop(Canvas canvas) {
        if (mCurrentShowIndex >= 0 && !mWaves.isEmpty()) {
            WaveConfigData wave = mWaves.get(0);
            float value = wave.values[mCurrentShowIndex];

            float maxY = mCoordinateYValues[mCoordinateYCount - 1];// Y轴坐标的最大值
            float yHeight = mGridHeight * (mCoordinateYCount - 1);
            float x = getYCoordinator() + mGridWidth * mCurrentShowIndex;
            float y = getXCoordinator() - yHeight * (wave.values[mCurrentShowIndex] / maxY);

            // 绘制弹窗的圆角矩形
            float offsetY = y - mShowCircleRadius + mWrapPaint.getStrokeWidth();
            mWrapPaint.setStyle(Paint.Style.FILL);
            mWrapPaint.setColor(mShowBackgroundColor == 0 ? wave.color : mShowBackgroundColor);
            float triangleSize = 20;
            String text = String.format(Locale.getDefault(), "%.02f", value);
            float textWidth = mWrapPaint.measureText(text);
            float startX = x - mShowPaddingHorizontal - textWidth / 2f;
            float startY = offsetY - triangleSize - 2 * mShowPaddingVertical - mWrapPaint.getTextSize();
            canvas.drawRoundRect(startX, startY, startX + 2 * mShowPaddingHorizontal + textWidth,
                    startY + 2 * mShowPaddingVertical + mWrapPaint.getTextSize(), 15, 15, mWrapPaint);

            // 连线绘制圆角
            Path path = new Path();
            path.moveTo(x - triangleSize, offsetY - triangleSize - mWrapPaint.getStrokeWidth() / 2f);
            path.lineTo(x + triangleSize, offsetY - triangleSize - mWrapPaint.getStrokeWidth() / 2f);
            path.lineTo(x, offsetY);
            path.close();
            canvas.drawPath(path, mWrapPaint);

            // 写中间的字
            mWrapPaint.setColor(mShowTextColor);
            canvas.drawText(text, startX + mShowPaddingHorizontal,
                    startY + mShowPaddingVertical + mWrapPaint.getTextSize() / 2f + CanvasUtil.getDrawTextOffsetY(mWrapPaint),
                    mWrapPaint);

            // 先画圆环
            mWrapPaint.setStyle(Paint.Style.STROKE);
            mWrapPaint.setColor(wave.color);
            RectF rectF = new RectF();
            rectF.left = x - mShowCircleRadius;
            rectF.right = x + mShowCircleRadius;
            rectF.top = y - mShowCircleRadius;
            rectF.bottom = y + mShowCircleRadius;
            canvas.drawArc(rectF, 360, 360, false, mWrapPaint);

            // 再画白色圆圈叠加在中间进行遮挡
            mWrapPaint.setStyle(Paint.Style.FILL);
            mWrapPaint.setColor(Color.WHITE);
            canvas.drawCircle(x, y, mShowCircleRadius - mWrapPaint.getStrokeWidth() / 2, mWrapPaint);
        }
    }

    private int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dp, getResources().getDisplayMetrics());
    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                sp, getResources().getDisplayMetrics());
    }

    private int mCurrentShowIndex = -1;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mWaves.isEmpty()) return super.onTouchEvent(event);

        if (event.getAction() == MotionEvent.ACTION_UP) {
            // 隐藏信息弹窗
            mCurrentShowIndex = -1;
            invalidate();
        } else {
            // 展示信息弹窗
            float x = event.getX();
            int start, center, end;
            int needShowIndex = -1;
            for (int i = 0; i < mCoordinateXValues.length; i++) {
                center = getYCoordinator() + mGridWidth * i;
                if (i == 0) {
                    start = center;
                    end = center + mGridWidth / 2;
                } else if (i == mCoordinateXValues.length - 1) {
                    start = center - mGridWidth / 2;
                    end = center;
                } else {
                    start = center - mGridWidth / 2;
                    end = center + mGridWidth / 2;
                }
                if (x >= start && x <= end) {
                    needShowIndex = i;
                    break;
                }
            }
            if (needShowIndex >= 0 && needShowIndex != mCurrentShowIndex) {
                mCurrentShowIndex = needShowIndex;
                invalidate();
            }
        }
        Log.i("WaveView", "currentShowIndex: " + mCurrentShowIndex);
        return true;
    }

    public static class WaveConfigData {
        int color;
        int linearGradientEndColor;
        boolean isCoverRegion;
        float[] values;
        int dashStartPoint = -1;

        public WaveConfigData(int color, boolean isCoverRegion, float[] values) {
            this(color, 0, isCoverRegion, values);
        }

        public WaveConfigData(int color, int linearGradientEndColor, boolean isCoverRegion, float[] values) {
            this.color = color;
            this.linearGradientEndColor = linearGradientEndColor;
            this.isCoverRegion = isCoverRegion;
            this.values = values;
        }
    }
}